﻿using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Text;

namespace Universe.CrossIO
{
    public class Reader
    {
        public static bool JReadBoolean(BinaryReader reader)
        {
            return reader.ReadByte() != 0;
        }
        
        public static long JRead7BitLong(BinaryReader reader)
        {
            long ret = 0;
            int shift = 0;
            do{
                if (shift == 56)
                    throw new IOException("Stream is corrupted");

                byte next = reader.ReadByte();
                ret |= (next & 0x7f) << shift;
                if (((next & 0x80) == 0))
                    break;

                shift += 7;
            } while (true);

            return ret;
        }

        public static long JReadLong(BinaryReader reader)
        {
            byte[] bytes = reader.ReadBytes(8);
            Array.Reverse(bytes);
            return BitConverter.ToInt64(bytes, 0);
        }

        public static int JReadInt(BinaryReader reader)
        {
            byte[] bytes = reader.ReadBytes(4);
            Array.Reverse(bytes);
            return BitConverter.ToInt32(bytes, 0);
        }

        public static short JReadShort(BinaryReader reader)
        {
            byte[] bytes = reader.ReadBytes(2);
            Array.Reverse(bytes);
            return BitConverter.ToInt16(bytes, 0);
        }

        public static Color JReadColor(BinaryReader reader)
        {
            int i = JReadInt(reader);
            return i == -1 ? Color.Empty : Color.FromArgb(i);
        }

        public static string JReadString(BinaryReader reader)
        {
            long len = JRead7BitLong(reader);
            if ((len & 1) == 0)
                return null;

            len = len >> 1;
            StringBuilder ret = new StringBuilder((int) len);
            for(int i=0; i<len; i++)
            {
                long c = JRead7BitLong(reader);
                char ch = (char) (int) c;
                ret.Append(ch);
            }

            return ret.ToString();
        }

        public static Guid JReadGuid(BinaryReader reader)
        {
            bool isEmpty = reader.ReadByte() != 0;
            if (isEmpty)
                return Guid.Empty;

            else
            {
                byte[] bytes = reader.ReadBytes(16);
                if (bytes.Length != 16)
                    throw new IOException("Unexpected end of stream during reading GUID");

                return new Guid(bytes);
            }
        }

        public static decimal JReadDecimal(BinaryReader reader)
        {
            return JReadLong(reader)/(decimal) 10000;
        }

        public static DateTime JReadDateTime(BinaryReader reader)
        {
            return Constants.JZeroDate.AddMilliseconds(JReadLong(reader));
        }

        public static DateTime JReadDay(BinaryReader reader)
        {
            byte int8 = reader.ReadByte();
            byte[] bytesInt16 = reader.ReadBytes(2);
            Array.Reverse(bytesInt16);
            short int16 = BitConverter.ToInt16(bytesInt16, 0);
            int dayKey = ((((int) int16) & 0xFFFF) << 8) | (int) int8;
            int year = dayKey/366;
            int dayOfYear = dayKey%366;
            DateTime ret = new DateTime(year, 1, 1).AddDays(dayOfYear);
            return ret;
        }
    }
}
